package com.zhike.utils;

import java.util.ArrayList;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.gson.Gson;
import com.zhike.mobileimsdk.server.network.MBObserver;
import com.zhike.mobileimsdk.server.protocal.Protocal;
import com.zhike.mobileimsdk.server.protocal.ProtocalFactory;
import com.zhike.mobileimsdk.server.utils.GlobalSendHelper;
import com.zhike.common.dto.UserRosterVO;
import com.zhike.service.im.manager.MessageRecordManager;
import com.zhike.service.im.manager.OfflineMessageManager;
import com.zhike.service.messages.IChatSessionService;
import com.zhike.utils.cache.GroupsInfoCacheProvider;
import com.zhike.utils.manager.UsersStatusManager;
import com.zhike.common.dto.CMDBody4GroupNameChangedNotification;
import com.zhike.common.dto.CMDBody4MyselfBeInvitedGroupResponse;
import com.zhike.common.dto.CMDBody4RevokeMessageRequest;
import com.zhike.common.dto.CMDBodyAddFriendRequest;
import com.zhike.common.dto.CMDBodyC2CBeforeRequest;
import com.zhike.common.dto.CMDBodyReadedMessageRequest;
import com.zhike.common.dto.FriendRequestProcessDTO;
import com.zhike.common.dto.GroupInfo4Cache;
import com.zhike.common.dto.GroupMemberEntity;
import com.zhike.common.dto.MsgBody4Group;
import com.zhike.common.dto.MsgBody4Guest;
import com.zhike.common.dto.MsgBodyRoot;
import com.zhike.common.dto.MsgType;
import com.zhike.common.dto.MsgBodyGroupS2C;
import com.zhike.common.dto.UserProtocalsType;
import com.zhike.common.repository.HistoryMessage;
import com.zhike.common.vo.UserInfo4Cache;
import com.zhike.common.vo.UserInfoVO;

import lombok.extern.slf4j.Slf4j;

/**
 * 服务端主动发出的或收到的消息处理辅助类（即消息发送模式为C2S或S2C的情况）.
 * 
 * @version 1.0
 */
@Slf4j
@Component
public class MessageHelper {
  @Resource
  private OfflineMessageManager offlineMessageManager;

  @Autowired
  private UsersStatusManager usersStatusManager;

  @Autowired
  private MessageRecordManager messageRecordManager;

  @Autowired
  private IChatSessionService chatSessionService;

  @Autowired
  private GroupsInfoCacheProvider groupsInfoCacheProvider;

  /**
   * 由服务端主动发起的一条消息。
   * 
   * @param to_user_id
   * @param message
   * @param QoS
   * @param typeu
   * @return
   * @throws Exception
   */
  public void sendMessage(String to_user_id, String message, boolean QoS, int typeu,
      SendResultObserver sendResultObserver) throws Exception {
    sendMessage(to_user_id, message, QoS, null, typeu, sendResultObserver);
  }

  /**
   * 由服务端主动发起的一条消息。
   * 
   * @param to_user_id
   * @param message
   * @param QoS
   * @param fingerPrint        当本参数为null时，将自动生成消息指纹码，否则使用参数指定的指纹码
   * @param typeu
   * @param sendResultObserver 指令发送结果观察者（因为通信底层netty是异步通知数据发送结果的）
   * @return
   * @throws Exception
   * @see SendResultObserver
   */
  public void sendMessage(String to_user_id, String message, boolean QoS, String fingerPrint, int typeu,
      final SendResultObserver sendResultObserver) throws Exception {

    final Protocal p = ProtocalFactory.createCommonData(message, "0", to_user_id, QoS, fingerPrint, typeu);
    if (message != null && message.length() > 0) {
      // netty是异步通知数据发送结果的
      MBObserver resultObserver = new MBObserver() {
        @Override
        public void update(boolean sucess, Object extraObj) {
          if (sendResultObserver != null)
            sendResultObserver.update(sucess, p);
        }
      };

      GlobalSendHelper.sendDataS2C(null, p, resultObserver);
    } else {
      log.error("[RainbowChat]message为null或length<=0，请检查参数.");

      if (sendResultObserver != null)
        sendResultObserver.update(false, p);
    }
  }

  // 上线消息是由服务端发出的，所以from_user_id==0（QoS==false主要用于发送上下线通知时，
  // 否则极端情况下重传的上线通知会后于下线通知，会搞乱上下线的通知罗辑）
  public void sendOnlineMessage(String to_user_id, String message, SendResultObserver sendResultObserver)
      throws Exception {
    // 用户上线通知的格式是：上线用户uid”
    // ，形如："400005"
    sendMessage(to_user_id, message, false, UserProtocalsType.MT01_OF_ONLINE_NOTIVICATION, sendResultObserver);
  }

  // 下线消息是由服务端发出的，所以from_user_id==0（QoS==false主要用于发送上下线通知时，
  // 否则极端情况下重传的上线通知会后于下线通知，会搞乱上下线的通知罗辑）
  public void sendOfflineMessage(String to_user_id, String userUid, SendResultObserver sendResultObserver)
      throws Exception {
    // 用户下线通知的格式是：“下线用户uid”
    // ，形如："400005"
    sendMessage(to_user_id, userUid, false, UserProtocalsType.MT02_OF_OFFLINE_NOTIVICATION, sendResultObserver);
  }

  // -------------------------------------------------------------------------------
  // 加好友请求处理相关 S
  /**
   * 由服务端反馈给加好友发起人的错误信息头(出错的可能是：该好友
   * 已经存在于我的好友列表中、插入好友请求到db中时出错等)。
   * 
   * @param to_user_id
   * @param errorMessage
   * @return
   * @throws Exception
   */
  // 此消息由服务端主动发起，所以from_user_id==0
  public void sendAddFriendRequestResponse_for$error_server$to$aMessage(String to_user_id, String errorMessage,
      SendResultObserver sendResultObserver) throws Exception {
    sendMessage(to_user_id// 当起人的user_id=0时，服务端的QoS机制才有意义哦！
        , errorMessage, true, UserProtocalsType.MT06_OF_ADD_FRIEND_REQUEST_RESPONSE$FOR$ERROR_SERVER$TO$A,
        sendResultObserver);
  }

  /**
   * 同意添加好友的请求
   */
  public void sendAddFriendAgree_server$to$Message(String to_user_id, String message,
      SendResultObserver sendResultObserver) throws Exception {
    sendMessage(to_user_id// 当起人的user_id=0时，服务端的QoS机制才有意义哦！
        , message, false, UserProtocalsType.MT08_OF_PROCESS_ADD$FRIEND$REQ_B$TO$SERVER_AGREE,
        sendResultObserver);
  }

  /**
   * 解析用户发起添加好友的请求消息
   * 
   * @param originalMsg
   * @return 客户端A发过来的加好友请求元数据封装对象
   */
  public CMDBodyAddFriendRequest pareseAddFriendRequestMessage(String originalMsg) {
    // 加好友请求原数据（客户端A发过来的）
    CMDBodyAddFriendRequest arm = new Gson().fromJson(
        originalMsg, CMDBodyAddFriendRequest.class);
    return arm;
  }

  /**
   * 由服务端转发的加好友请求消息给在线目标用户（离线用户是不需要的哦）.
   * 
   * @param to_user_id 要发送到的目标客户user_id
   * @return
   */
  public void sendAddFriendRequestInfo_server$to$bMessage(
      String to_user_id, UserInfo4Cache srcUserInfo, SendResultObserver sendResultObserver) throws Exception {
    String srcUserInfoStr = new Gson().toJson(srcUserInfo);
    sendMessage(to_user_id// 当起人的user_id=0时，服务端的QoS机制才有意义哦！
        , srcUserInfoStr, true, UserProtocalsType.MT07_OF_ADD_FRIEND_REQUEST_INFO_SERVER$TO$B, sendResultObserver);
  }

  /**
   * 删除好友消息
   *
   * @param to                 to
   * @param sendResultObserver sendResultObserver
   * @throws Exception 异常
   */
  public void sendDelFriendMsg_SERVER$TO$B_Message(String message, String to, SendResultObserver sendResultObserver)
      throws Exception {
    sendMessage(to, message, false, UserProtocalsType.MT61, sendResultObserver, null);

  }

  /**
   * 解析已读消息的MessgeIDs
   * 
   * @param originalMsg
   */
  public CMDBodyReadedMessageRequest parseReadedMessge(String originalMsg) {
    log.debug("接收到已读消息原数据:{}", originalMsg);
    CMDBodyReadedMessageRequest request = new Gson().fromJson(originalMsg, CMDBodyReadedMessageRequest.class);
    return request;
  }

  public CMDBody4RevokeMessageRequest parseRevokeMessage(String originalMsg) {
    CMDBody4RevokeMessageRequest request = new Gson().fromJson(originalMsg, CMDBody4RevokeMessageRequest.class);
    return request;
  }

  public CMDBodyC2CBeforeRequest parseC2CMessage(String originalMsg) {
    CMDBodyC2CBeforeRequest request = new Gson().fromJson(originalMsg, CMDBodyC2CBeforeRequest.class);
    return request;
  }

  /**
   * 由服务端主动发起的一条消息。
   *
   * @param to_user_id to_user_id
   * @param message    message
   * @param QoS        QoS
   * @param typeu      typeu
   * @throws Exception
   */
  public void sendMessage(String to_user_id, String message, boolean QoS, int typeu,
      SendResultObserver sendResultObserver, String fingerPrint) throws Exception {
    sendMessage(to_user_id, message, QoS, fingerPrint, typeu, sendResultObserver);
  }

  /**
   * 由服务端转发的入群邀请请求消息给在线目标用户（离线用户是不需要的哦）.
   *
   * @param to_user_id 要发送到的目标客户user_id
   */
  public void sendAddGroupRequestInfo_server$to$bMessage(
      String to_user_id, String msg, SendResultObserver sendResultObserver) throws Exception {
    sendMessage(to_user_id// 当起人的user_id=0时，服务端的QoS机制才有意义哦！
        , msg, true, UserProtocalsType.MT53, sendResultObserver, null);
  }

  /**
   * 解析用户B发起的处理被添加好友的请求消息：处理动作——【同意】.
   * 
   * @param originalMsg
   * @return 客户端B发过来的加好友请求元数据封装对象
   */
  public static FriendRequestProcessDTO pareseProcessAddFriendMessage(String originalMsg) {
    // 加好友请求原数据（客户端A发过来的）
    FriendRequestProcessDTO arm = new Gson().fromJson(originalMsg, FriendRequestProcessDTO.class);
    return arm;
  }

  /**
   * 新好友已成功被添加后，由服务端把好友信息实时反馈给客户端（
   * 此场景是被请求用户同意了加好友的请求时，由服务端把双 方的好友信息及时交给对方（如果双方有人在线的话））.
   * 
   * @param to_user_id 要发送到的目标客户user_id
   * @return
   */
  // 此消息由服务端主动发起，所以from_user_id==0
  public void sendProcessAddFriendReq(
      String to_user_id, UserRosterVO userInfo, SendResultObserver sendResultObserver) throws Exception {
    String userInfoStr = new Gson().toJson(userInfo);
    sendMessage(to_user_id// 当起人的user_id=0时，服务端的QoS机制才有意义哦！
        , userInfoStr, true, UserProtocalsType.MT10_OF_PROCESS_ADD$FRIEND$REQ_FRIEND$INFO$SERVER$TO$CLIENT,
        sendResultObserver);
  }

  /**
   * 由服务端反馈给B处理加好友请求处理时的错误信息(出错的可能是：B在提交同意A的加好友请求时出错了等)。
   * 
   * @param to_user_id
   * @param errorMessage
   * @return
   * @throws Exception
   */
  // 此消息由服务端主动发起，所以from_user_id==0
  public void sendProcessAddFriendReq_response$For$Rrror_server$to$bMessage(
      String to_user_id, String errorMessage, SendResultObserver sendResultObserver) throws Exception {
    sendMessage(to_user_id// 当起人的user_id=0时，服务端的QoS机制才有意义哦！
        , errorMessage, true, UserProtocalsType.MT11_OF_PROCESS_ADD$FRIEND$REQ_RESPONSE$FOR$ERROR_SERVER$TO$B,
        sendResultObserver);
  }

  /**
   * A的加好友请求被B拒绝后，由服务端把拒绝信息实时反馈给客户端A（以便A能实时知道加好友被拒的情况）.
   * 
   * <p>
   * 当然，此消息被发送的前提条件是A用户此时是在线的。
   * 
   * @param to_user_id 要发送到的目标客户user_id
   * @return
   */
  // 此消息由服务端主动发起，所以from_user_id==0
  public void sendProcessAddFriendReqReject(
      String to_user_id, UserInfoVO userInfo, SendResultObserver sendResultObserver) throws Exception {
    String userInfoStr = new Gson().toJson(userInfo);
    sendMessage(to_user_id// 当起人的user_id=0时，服务端的QoS机制才有意义哦！
        , userInfoStr, true, UserProtocalsType.MT12_OF_PROCESS_ADD$FRIEND$REQ_SERVER$TO$A_REJECT_RESULT,
        sendResultObserver);

  }
  // -------------------------------------------------------------------------------
  // 加好友请求处理相关 E

  // -------------------------------------------------------------------------------
  // 临时聊天消息处理相关S
  /**
   * 陌生人聊天消息：由服务端转发给接收人B的【步骤2/2】.
   * 
   * <p>
   * 当然，此消息被发送的前提条件是B用户此时是在线的（否则临时聊天消息将被存储到DB中）。
   * 
   * @param to_user_id 要发送到的目标客户user_id
   * @return
   */
  // 此消息由服务端主动发起，所以from_user_id==0
  public void sendTempChatMsg_SERVER$TO$B_Message(
      String to_user_id, MsgBody4Guest tempChatMsgDTO, String fingerPrint, SendResultObserver sendResultObserver)
      throws Exception {
    String tempChatMsgDTOStr = new Gson().toJson(tempChatMsgDTO);
    sendMessage(to_user_id, tempChatMsgDTOStr, true, fingerPrint, UserProtocalsType.MT43_OF_TEMP$CHAT$MSG_SERVER$TO$B,
        sendResultObserver);

  }

  /**
   * 解析临时聊天消息：由发送人A发给服务端【步骤1/2】.
   * 
   * @param originalMsg
   * @return 客户端A发过来的临时聊天消息：由发送人A发给服务端【步骤1/2】元数据封装对象
   */
  public static MsgBody4Guest pareseTempChatMsg_A$TO$SERVER_Message(String originalMsg) {
    // 元数据（客户端A发过来的）
    MsgBody4Guest tcmd = new Gson().fromJson(originalMsg, MsgBody4Guest.class);
    return tcmd;
  }
  // -------------------------------------------------------------------------------
  // 临时聊天消息处理相关 E

  // -------------------------------------------------------------------------------
  // 群聊聊天消息处理相关S
  /**
   * 群聊/世界频道聊天消息：由服务端转发给接收人B的【步骤2/2】.
   * 
   * <p>
   * 当然，此消息被发送的前提条件是B用户此时是在线的（否则BBS聊天消息将不会被发送给此人哦（会自动丢弃））。
   * 
   * @param to_user_id 要发送到的目标客户user_id
   * @return
   */
  // 此消息由服务端主动发起，所以from_user_id==0，但此参数目前对于接收方而言没有用处，以后可能会用上
  public void sendGroupChatMsg_SERVER$TO$B_Message(
      String to_user_id, MsgBody4Group groupChatMsgDTO, SendResultObserver sendResultObserver) throws Exception {
    String groupChatMsgDTOStr = new Gson().toJson(groupChatMsgDTO);
    sendMessage(to_user_id, groupChatMsgDTOStr, false, UserProtocalsType.MT45_OF_GROUP$CHAT$MSG_SERVER$TO$B,
        sendResultObserver);
  }

  public void sendGroupChatMsg_STOC_Message(String to_user_id, MsgBody4Group groupChatMsgDTO, String fp,
      SendResultObserver sendResultObserver) throws Exception {
    String groupChatMsgDTOStr = new Gson().toJson(groupChatMsgDTO);
    sendMessage(to_user_id, groupChatMsgDTOStr, false, fp, UserProtocalsType.MT45_OF_GROUP$CHAT$MSG_SERVER$TO$B,
        sendResultObserver);
  }

  /**
   * 解析群聊/世界频道聊天消息：由发送人A发给服务端【步骤1/2】.
   * 
   * @param originalMsg
   * @return 客户端A发过来的BBS/群组聊天消息：由发送人A发给服务端【步骤1/2】元数据封装对象
   */
  public static MsgBody4Group pareseGroupChatMsg_A$TO$SERVER_Message(String originalMsg) {
    // 元数据（客户端A发过来的）
    MsgBody4Group tcmd = new Gson().fromJson(originalMsg, MsgBody4Group.class);
    return tcmd;
  }

  public static MsgBodyRoot pareseChatMsg_ROOT_Message(String originalMsg) {
    // 元数据（客户端A发过来的）
    MsgBodyRoot tcmd = new Gson().fromJson(originalMsg, MsgBodyRoot.class);
    return tcmd;
  }

  /**
   * 创建群，服务端发的，群发到客户端的数据
   * 
   * @param sessionId
   * @param deviceNo
   * @param ownerUid
   * @param inviteBeNickName 邀请人昵称
   * @param groupInfo        群信息
   * @param fp               指纹码
   * @throws Exception
   */
  public void sendGroupSysCMD4Message(String sessionId, String deviceNo, String ownerUid,
      String inviteBeNickName, GroupInfo4Cache groupInfo, ArrayList<GroupMemberEntity> newJoinedMemberList, String fp)
      throws Exception {
    MsgBodyGroupS2C cmdBody = new MsgBodyGroupS2C();
    cmdBody.setUserId(ownerUid);
    cmdBody.setNickname(inviteBeNickName);
    cmdBody.setGroupName(groupInfo.getGname());
    cmdBody.setGroupId(groupInfo.getGid());
    cmdBody.setCGroup(1);
    cmdBody.setMembers(newJoinedMemberList);
    MsgBodyRoot root = new MsgBodyRoot();
    root.setCy(2);// 群聊
    root.setTy(MsgType.TYPE_CREATEGROUP); // 创建群或邀请成员
    root.setM(new Gson().toJson(cmdBody));
    sendGroupSysCMD(sessionId, UserProtocalsType.MT45_OF_GROUP$CHAT$MSG_SERVER$TO$B, "群聊CMD-通知新加者",
        deviceNo,
        ownerUid,
        root, MsgType.TYPE_CREATEGROUP, groupInfo.getGid(), "", fp);
  }

  /**
   * 群聊系统指令：“我”加群成功后通知“我”（即通知被加群者）（由Server发出）。
   * <p>
   * “我”可能是在创建群或群建好后邀请进入的.
   */
  public void sendGroupSysCMD4MyselfBeInvited(String sessionId, String toUid, String inviteBeUid,
      String inviteBeNickName, GroupInfo4Cache groupInfo, String fp) throws Exception {
    String offlineContent = "\"" + inviteBeNickName + "\"邀请你加入了群聊";

    // 准备好要发送的数据内容
    CMDBody4MyselfBeInvitedGroupResponse cmdBody = new CMDBody4MyselfBeInvitedGroupResponse();
    cmdBody.setInviteBeUid(inviteBeUid);
    cmdBody.setInitveBeNickName(inviteBeNickName);
    MsgBodyRoot root = new MsgBodyRoot();
    root.setM(new Gson().toJson(cmdBody));
    sendGroupSysCMD(sessionId, UserProtocalsType.MT46_OF_GROUP$SYSCMD_MYSELF$BE$INVITE_FROM$SERVER, "群聊CMD-通知新加者",
        toUid,
        inviteBeUid,
        root, 0, groupInfo.getGid(), offlineContent, fp);
  }

  /**
   * 群聊系统指令：发出一条通用的系统信息给指定群员（由Server发出）。
   */
  public void sendGroupSysCMD4CommonInfo(String sessionId, String deviceNo, String toUid, String systemInfo, String gid,
      String fp)
      throws Exception {
    // String notificationContent =
    // "\""+inviteBeNickName+"\"邀请\""+newJoinNickName+"\"加入了群聊";
    MsgBody4Group body = MsgBody4Group.constructGroupSystenMsgBody(gid, systemInfo);
    MsgBodyRoot root = new MsgBodyRoot();
    root.setM(new Gson().toJson(body));
    sendGroupSysCMD(sessionId, UserProtocalsType.MT47_OF_GROUP$SYSCMD_COMMON$INFO_FROM$SERVER, "群聊CMD-通用通知", deviceNo,
        toUid,
        root, 0, gid, systemInfo, fp);
  }

  /**
   * 群聊系统指令：发出一条群已被解散通知（由Server发出，除解散者外的所有人接收） 。
   */
  public void sendGroupSysCMD4Dismissed(String sessionId, String deviceNo, String toUid, String dismissUserName,
      String gid, String fp)
      throws Exception {
    String notificationContent = "本群已被\"" + dismissUserName + "\"解散";
    MsgBody4Group body = MsgBody4Group.constructGroupSystenMsgBody(gid, notificationContent);
    MsgBodyRoot root = new MsgBodyRoot();
    root.setM(new Gson().toJson(body));
    sendGroupSysCMD(sessionId, UserProtocalsType.MT48_OF_GROUP$SYSCMD_DISMISSED_FROM$SERVER, "群聊CMD-解散通知", deviceNo,
        toUid,
        root, 0, gid, notificationContent, fp);
  }

  /**
   * 群聊系统指令：发出一条"你"被踢出群聊（由Server发出，被踢者接收）。
   */
  public void sendGroupSysCMD4YouBeRemoved(String sessionId, String deviceNo, String toUid, String ownerNickname,
      String gid, String fp)
      throws Exception {
    String notificationContent = "你已被\"" + ownerNickname + "\"移出本群";
    MsgBody4Group body = MsgBody4Group.constructGroupSystenMsgBody(gid, notificationContent);
    MsgBodyRoot root = new MsgBodyRoot();
    root.setM(new Gson().toJson(body));
    sendGroupSysCMD(sessionId, UserProtocalsType.MT49_OF_GROUP$SYSCMD_YOU$BE$KICKOUT_FROM$SERVER, "群聊CMD-你被踢通知",
        deviceNo, toUid,
        root, 0, gid, notificationContent, fp);
  }

  /**
   * 群聊系统指令：发出一条"别人"主动退出或被群主踢出群聊（由Server发出，其它群员接收） 。
   * 
   * @param himselfQuitGroup true表示本次是该人自已退群的，否则是被群主删除的
   */
  public void sendGroupSysCMD4SomeoneRemoved(String sessionId, boolean himselfQuitGroup, String deviceNo, String toUid,
      String delOprNickname,
      String beRemovedNickname, String gid, String fp) throws Exception {
    String notificationContent = null;

    if (himselfQuitGroup)
      notificationContent = "\"" + beRemovedNickname + "\"已退出本群";
    else
      notificationContent = "\"" + beRemovedNickname + "\"已被\"" + delOprNickname + "\"移出本群";

    MsgBody4Group body = MsgBody4Group.constructGroupSystenMsgBody(gid, notificationContent);
    MsgBodyRoot root = new MsgBodyRoot();
    root.setM(new Gson().toJson(body));
    sendGroupSysCMD(sessionId, UserProtocalsType.MT50_OF_GROUP$SYSCMD_SOMEONEB$REMOVED_FROM$SERVER, "群聊CMD-别人退群或被踢出通知",
        deviceNo,
        toUid,
        root, 0, gid, notificationContent, fp);
  }

  /**
   * 群聊系统指令：群名被修改的系统通知（由Server发出，所有除修改者外的群员接收）。
   */
  public void sendGroupSysCMD4GroupNameChanged(String sessionId, String deviceNo, String toUid, String changedByUid,
      String changedByNickName,
      String newGroupName, String gid, String fp) throws Exception {
    String notificationContent = "\"" + changedByNickName + "\"修改群名为\"" + newGroupName + "\"";

    // 准备好要发送的数据内容
    CMDBody4GroupNameChangedNotification cmdBody = new CMDBody4GroupNameChangedNotification();
    cmdBody.setChangedByUid(changedByUid);
    cmdBody.setNnewGroupName(newGroupName);
    cmdBody.setNotificationContent(notificationContent);
    cmdBody.setGid(gid);
    MsgBodyRoot root = new MsgBodyRoot();
    root.setM(new Gson().toJson(cmdBody));
    sendGroupSysCMD(sessionId, UserProtocalsType.MT51_OF_GROUP$SYSCMD_GROUP$NAME$CHANGED_FROM$SERVER, "群聊CMD-群名被改",
        deviceNo,
        toUid,
        root, 0, gid, notificationContent, fp);
  }

  /**
   * 发送群聊的系统级指令或通知（当接收者不在线时，本方法将自动进行离线处理）。
   * 
   * @param typeu             协议类型
   * @param logTag            日志TAG
   * @param deviceNo          设备ID
   * @param toUid             发送的对象
   * @param cmdBodyStr        要发送的协议体内容（可能是个JSON，也可能只是普通文本）
   * @param gid               发生的群id
   * @param gname             发生的群名称
   * @param contentForOffline 如果接收者不在线时，要离线保存的内容
   * @throws Exception
   */
  private void sendGroupSysCMD(String sessionId, int typeu, final String logTag, String deviceNo, String toUid,
      MsgBodyRoot msgBody, int msgType,
      String gid,
      String contentForOffline, String fp) throws Exception {
    String cmdBodyStr = new Gson().toJson(msgBody);
    if (cmdBodyStr != null) {
      // 本实例中是否在线
      final boolean isOnline = usersStatusManager.isOnline(deviceNo);

      SendResultObserver sendResultObserver = new SendResultObserver() {
        @Override
        public void update(boolean code, Protocal p) {
          if (code) {
            log.info("[ZKIMChat]【{}】Server向群:{}  发送通知已成功实时发出！", logTag, gid);

          }
        }
      };

      if (isOnline) {
        // 为了保证群系统通知的送达率，也启用了QoS机制哦
        sendMessage(deviceNo, cmdBodyStr, true, typeu, sendResultObserver);
      }

      HistoryMessage hm = messageRecordManager.colectGroupMsgAsync(sessionId, "0", toUid, gid, 2, msgType,
          msgBody.getM(),
          fp);
      if (hm != null) {
        GroupInfo4Cache gc = groupsInfoCacheProvider.get(gid);
        chatSessionService.updateGroupSession(hm, gc.getGname(), "");
      }
    } else {
      log.warn("[ZKIMChat]【" + logTag + "】cmdBodyStr is null! (toUid=" + toUid
          + ", gid=" + gid + ", , contentForOffline=" + contentForOffline + ")");
    }
  }
  // -------------------------------------------------------------------------------
  // 群聊聊天消息处理相关 E

  // /**
  // * 消息发送结果封装类。
  // */
  // public static class SendResult
  // {
  // // 发送结果：true表示成功发出，否则发出失败
  // private boolean code = false;
  // // 发送内容：返回本次发送的完整协议包内容（只是方便调用者后绪 使用，不是必须要用的）。
  // private Protocal p;
  //
  // public SendResult(boolean code, Protocal p)
  // {
  // this.code = code;
  // this.p = p;
  // }
  //
  // public boolean isCode()
  // {
  // return code;
  // }
  //
  // public Protocal getP()
  // {
  // return p;
  // }
  // }

  /**
   * 消息发送结果封装类。
   */
  public static interface SendResultObserver {
    // // 发送结果：true表示成功发出，否则发出失败
    // private boolean code = false;
    // // 发送内容：返回本次发送的完整协议包内容（只是方便调用者后绪 使用，不是必须要用的）。
    // private Protocal p;
    //
    // public SendResultObserver(boolean code, Protocal p)
    // {
    // this.code = code;
    // this.p = p;
    // }
    //
    // public boolean isCode()
    // {
    // return code;
    // }
    //
    // public Protocal getP()
    // {
    // return p;
    // }

    /**
     * 发送指令完成后，通过此方法来通知异步结果的观察者。
     * 
     * @param code 指令发送结果：true表示成功发出，否则发出失败
     * @param p    指令发送内容：返回本次发送的完整协议包内容（只是方便调用者后绪 使用，不是必须要用的）
     */
    public void update(boolean code, Protocal p);
  }

}
